﻿/******************************************************************************
 * 
 * Announce: CSharpKit, Basic algorithms, components and definitions.
 *           Copyright (C) ShenYongchen.
 *           All rights reserved.
 *   Author: 申永辰.郑州 (shenyczz@163.com)
 *  WebSite: http://github.com/shenyczz/CSharpKit
 *
 * THIS CODE IS LICENSED UNDER THE MIT LICENSE (MIT).
 * THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF 
 * ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
 * IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
 * PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
 * 
******************************************************************************/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;

namespace CSharpKit.SVM
{
    /// <summary>
    /// 名称：样本数据集<br/>
    /// 例子：<br/>
    /// 1 1:0.68421 2:-0.616601 3:0.144385<br/>
    /// 1 1:0.18947 2:-0.513834 3:0.411765<br/>
    /// 2 1:-0.2947 2:-0.920949 3:-0.92357<br/>
    /// 2 1:-0.3157 2:-0.857708 3:-0.01605<br/>
    /// 3 1:-0.1211 2:0.1106721 3:0.069516<br/>
    /// 3 1:-0.2211 2:-0.802372 3:-0.04812<br/>
    /// </summary>
    [Serializable]
    public class SvmProblem : IEquatable<SvmProblem>
    {
        #region Constructots

        public SvmProblem()
        {
        }

        /// <summary>
        /// 构造样本集
        /// </summary>
        /// <param name="count">标签数量</param>
        /// <param name="y">标签集</param>
        /// <param name="x">节点集</param>
        /// <param name="maxIndex">节点索引最大值</param>
        internal SvmProblem(int count, double[] y, SvmNode[][] x, int maxIndex)
        {
            Count = count;
            Y = y;
            X = x;
            MaxIndex = maxIndex;
        }

        #endregion


        #region Properties

        /// <summary>
        /// 样本数量=>LabelCount
        /// </summary>
        public int Count { get; internal set; }
        /// <summary>
        /// 标签集
        /// </summary>
        public double[] Y { get; internal set; }
        /// <summary>
        /// 节点集(dim0=label_Count, dim1=node_count)
        /// </summary>
        public SvmNode[][] X { get; internal set; }
        /// <summary>
        /// 节点索引最大值=>NodeCount
        /// </summary>
        /// <value></value>
        public int MaxIndex { get; internal set; }

        #endregion




        /// <summary>
        /// 读取数据集
        /// </summary>
        /// <param name="filename"></param>
        /// <returns></returns>
        public static SvmProblem Read(string filename)
        {
            SvmProblem result = null;

            try
            {
                FileStream input = File.OpenRead(filename);
                result = Read(input);
                input.Close();
            }
            catch (Exception ex)
            {
#if DEBUG
                Debug.WriteLine(ex);
#endif
            }

            return result;
        }
        public static SvmProblem Read(Stream stream)
        {
            TemporaryCulture.Start();

            StreamReader input = new StreamReader(stream);

            int max_index = 0;
            List<double> vy = new List<double>();
            List<SvmNode[]> vx = new List<SvmNode[]>();

            while (input.Peek() > -1)
            {
                string[] parts = input.ReadLine().Trim().Split();

                vy.Add(double.Parse(parts[0]));

                int m = parts.Length - 1;
                SvmNode[] x = new SvmNode[m];
                for (int j = 0; j < m; j++)
                {
                    x[j] = new SvmNode();
                    string[] nodeParts = parts[j + 1].Split(':');
                    x[j].Index = int.Parse(nodeParts[0]);
                    x[j].Value = double.Parse(nodeParts[1]);
                }

                if (m > 0)
                    max_index = System.Math.Max(max_index, x[m - 1].Index);

                vx.Add(x);
            }

            TemporaryCulture.Stop();

            return new SvmProblem(vy.Count, vy.ToArray(), vx.ToArray(), max_index);
        }


        public static void Write(string filename, SvmProblem problem)
        {
            FileStream output = File.Open(filename, FileMode.Create);
            try
            {
                Write(output, problem);
            }
            finally
            {
                output.Close();
            }
        }
        public static void Write(Stream stream, SvmProblem problem)
        {
            TemporaryCulture.Start();

            var output = new StreamWriter(stream);
            for (int i = 0; i < problem.Count; i++)
            {
                output.Write(problem.Y[i]);
                for (int j = 0; j < problem.X[i].Length; j++)
                {
                    output.Write(" {0}:{1:0.000000}", problem.X[i][j].Index, problem.X[i][j].Value);
                }
                output.Write("\n");
            }
            output.Flush();

            TemporaryCulture.Stop();
        }




        #region Override functions

        public bool Equals(SvmProblem other)
        {
            return true
                && other != null
                && Count == other.Count
                && Y.IsEqual(other.Y)
                && X.IsEqual(other.X)
                && MaxIndex == other.MaxIndex
                ;
        }

        public override bool Equals(object obj)
        {
            return Equals(obj as SvmProblem);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode()
                ^ Count.GetHashCode()
                ^ MaxIndex.GetHashCode()
                ^ Y.ComputeHashcode()
                ^ X.ComputeHashcode()
                ;
        }

        public override string ToString()
        {
            return base.ToString();
        }

        #endregion


        //}}@@@
    }

}
